import json
from contextlib import asynccontextmanager

from fastapi import APIRouter, HTTPException, Depends
from pydantic import BaseModel

from config.RedisManager import RedisManager



# 最简单的Redis客户端创建方式
# 这种创建方式是每次操作都会创建新连接，在生产中一般不这样使用
# redis_client = redis.Redis(
#     host="127.0.0.1",           # Redis服务地址
#     port=16379,                 # Redis服务端口
#     db=0,                       # Redis数据库索引,默认值就是0
#     decode_responses=True       # 默认情况下，Redis返回的都是字节，设置decode_responses=True，则返回字符串
# )

# 使用连接池，这是推荐的方式
# 连接池可以复用连接，从而提高性能
# redis_pool = redis.ConnectionPool(
#     host="127.0.0.1",
#     port=16379,
#     db=0,
#     decode_responses=True,
#     max_connections=20     # 最大连接数
# )
#
# # 定义一个依赖项函数，用来返回Redis客户端
# async def get_redis_client():
#     redis_client = redis.Redis(connection_pool=redis_pool)
#     try:
#         yield redis_client
#     finally:
#         if redis_client:
#             await redis_client.close()


# 创建Redis连接池
# redis_pool = redis.ConnectionPool(
#     host="127.0.0.1",
#     port=16379,
#     db=0,
#     decode_responses=True,
#     max_connections=20
# )
# # 创建redis客户端
# redis_client = None

redis_manager = RedisManager()

@asynccontextmanager
async def get_redis_client(router: APIRouter):
    await redis_manager.connect()
    yield
    await redis_manager.disconnect()

router = APIRouter(lifespan=get_redis_client)

@router.get("/")
async def root():
    try:
        # 测试连接
        await redis_manager.redis.ping()
        return {"message": "Redis连接成功"}
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Redis 连接失败：{str(e)}")


# ------------- 字符串基本操作 --------------
class KeyValue(BaseModel):
    key: str
    value: str
    expire: int | None = None # 键值对超时时间,单位是秒

@router.post("/set")
async def set_key(key_value: KeyValue):
    """设置键值对"""
    try:
        if key_value.expire:
            # 带超时时间的键值对(使用setex)
            await redis_manager.redis.setex(
                key_value.key,
                key_value.expire,
                key_value.value
            )
            return {
                "message": "键值对设置成功",
                "key": key_value.key,
                "value": key_value.value,
                "expire": key_value.expire
            }
        else:
            # 不带超时时间的键值对(使用set)
            await redis_manager.redis.set(
                key_value.key,
                key_value.value
            )
            return {
                "message": "键值对设置成功",
                "key": key_value.key,
                "value": key_value.value
            }
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"键值对设置失败：{str(e)}")

@router.get("/get/{key}")
async def get_key(key:str):
    """获取键值对"""
    try:
        value = await redis_manager.redis.get(key)
        return {
            "message": "键值对获取成功",
            "key": key,
            "value": value
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"键值对获取失败：{str(e)}")

@router.delete("/delete/{key}")
async def delete_key(key:str):
    """删除键值对"""
    try:
        await redis_manager.redis.delete(key)
        return {
            "message": "键值对删除成功",
            "key": key
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"键值对删除失败：{str(e)}")

@router.put("/increment/{key}")
async def increment_key(key:str, amount: int = 1):
    """递增键对应的值（适用于数值）"""
    try:
        # 这里递值的时候如果键不存在会自动创建这么一个键默认值是0再递增1也就是value最终会为1
        value = await redis_manager.redis.incrby(key, amount)
        return {
            "message": "键值对递增成功",
            "key": key,
            "value": value
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"键值对递增失败：{str(e)}")

@router.get("/exists/{key}")
async def exists_key(key:str):
    """判断键是否存在"""
    try:

        #  这里如果键存在则返回1，不存在返回0
        exists = await redis_manager.redis.exists(key)
        return {
            "message": "键是否存在成功",
            "key": key,
            "exists": exists
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"键是否存在失败：{str(e)}")

#------------------ 批量操作 ---------------------
@router.post("/mset")
async def multi_set(data: dict[str,str]):
    """批量设置键值对"""
    try:
        await redis_manager.redis.mset(data)
        return {
            "message": "批量设置键值对成功",
            "data": data
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"批量设置键值对失败：{str(e)}")

@router.post("/mget")
async def multi_get(keys: list[str]):
    """批量获取多个键的值"""
    try:
        values = await redis_manager.redis.mget(keys)
        result = {}
        # 使用keys和values两个列表配对，遍历它们的元素，将键值对添加到结果字典中
        for key, value in zip(keys, values):
            result[key] = value
        return result
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"批量获取键值对失败：{str(e)}")

@router.post("/pipeline")
async def pipeline_operations(operations: list[dict[str,str]]):
    """管道操作"""
    try:
        pipe = redis_manager.redis.pipeline()
        for op in operations:
            command=op.get("command")
            key = op.get("key")
            value = op.get("value")

            if command == "set" and key and value:
                pipe.set(key, value)
            elif command == "get" and key:
                pipe.get(key)
            elif command == "delete" and key:
                pipe.delete(key)
        results = await pipe.execute()
        return {
            "message": "管道操作成功",
            "results": results
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"管道操作失败：{str(e)}")


#----------------- 列表操作 -----------------
@router.post("/lpush/{key}")
async def list_left_push(key:str, value:str):
    """列表左边添加元素"""
    try:
        length = await redis_manager.redis.lpush(key,value)
        return {"message":f"元素已插入到列表 '{key}' 左侧","length": length}
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"列表添加元素失败：{str(e)}")

@router.post("/rpush/{key}")
async def list_right_push(key:str, value:str):
    """列表右边添加元素"""
    try:
        length = await redis_manager.redis.rpush(key,value)
        return {"message":f"元素已插入到列表 '{key}' 右侧","length": length}
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"列表添加元素失败：{str(e)}")


@router.get("/lpop/{key}")
async def list_left_pop(key: str):
    """列表左边弹出元素"""
    try:
        value = await redis_manager.redis.lpop(key)
        if not value:
            raise HTTPException(status_code=404, detail=f"列表 '{key}' 为空")
        return {"message":f"已从列表 '{key}' 左侧弹出元素","value": value}
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"列表弹出元素失败：{str(e)}")

@router.get("/rpop/{key}")
async def list_right_pop(key: str):
    """列表右边弹出元素"""
    try:
        value = await redis_manager.redis.rpop(key)
        if not value:
            raise HTTPException(status_code=404, detail=f"列表 '{key}' 为空")
        return {"message":f"已从列表 '{key}' 右侧弹出元素","value": value}
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"列表弹出元素失败：{str(e)}")


@router.get("/lrange/{key}")
async def list_range(key: str, start: int = 0, end: int = -1):
    """获取列表指定范围内的元素"""
    try:
        values = await redis_manager.redis.lrange(key, start, end)
        if not values:
            raise HTTPException(status_code=404, detail=f"列表 '{key}' 为空")
        return {"message":f"已获取列表 '{key}' 范围内的元素","values": values, "count": len(values)}
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"获取列表元素失败：{str(e)}")

@router.get("/llen/{key}")
async def list_length(key: str):
    """获取列表的长度"""
    try:
        length = await redis_manager.redis.llen(key)
        return {"message":f"已获取列表 '{key}' 的长度","length": length}
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"获取列表长度失败：{str(e)}")

#------------------ 哈希操作 --------------------
@router.post("/hset/{key}")
async def hash_key(key:str, field: str, value: str):
    """设置哈希字段的值"""
    try:
        result = await redis_manager.redis.hset(key, field, value)
        action = "更新" if result == 0 else "添加"
        return {"message":f"哈希字段{action}","key":key, "field": field, "value": value}
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"设置哈希字段值失败：{str(e)}")

@router.get("/hget/{key}")
async def hash_get(key: str, field: str):
    """获取哈希字段的值"""
    try:
        value = await redis_manager.redis.hget(key, field)
        if not value:
            raise HTTPException(status_code=404, detail=f"哈希字段 '{field}' 不存在")
        return {"message":f"已获取哈希字段 '{field}' 的值","key":key, "field": field, "value": value}
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"获取哈希字段值失败：{str(e)}")

@router.post("/hmset/{key}")
async def hash_multi_set(key: str, data: dict[str,str]):
    """批量设置哈希字段的值"""
    try:
        result = await redis_manager.redis.hmset(key, data)
        return {"message":f"已批量设置哈希字段的值","key":key, "data": data}
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"批量设置哈希字段值失败：{str(e)}")

@router.get("/hgetall/{key}")
async def hash_get_all(key: str):
    """获取哈希的所有字段和值"""
    try:
        result = await redis_manager.redis.hgetall(key)
        if not result:
            raise HTTPException(status_code=404, detail=f"哈希 '{key}' 为空")
        return {"message":f"已获取哈希的所有字段和值","key":key, "result": result}
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"获取哈希字段值失败：{str(e)}")

@router.delete("/hdel/{key}")
async def hash_delete(key: str, field: str):
    """删除哈希字段"""
    try:
        result = await redis_manager.redis.hdel(key, field)
        if result == 0:
            raise HTTPException(status_code=404, detail=f"哈希字段 '{field}' 不存在")
        return {"message":f"已删除哈希字段{key} - {field}"}
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"删除哈希字段失败：{str(e)}")

@router.get("/hexists/{key}")
async def hash_exists(key: str, field: str):
    """判断哈希字段是否存在"""
    try:
        result = await redis_manager.redis.hexists(key, field)
        return {"message":f"已判断哈希字段 '{field}' 是否存在","key":key, "field": field, "exists": result}
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"判断哈希字段是否存在失败：{str(e)}")

# --------------------- 简单缓存系统 -----------------------
# 模拟数据
fake_database = {
    1: {"id": 1, "name": "张三", "email": "zhangsan@example.com", "age": 25},
    2: {"id": 2, "name": "李四", "email": "lisi@example.com", "age": 30},
    3: {"id": 3, "name": "王五", "email": "wangwu@example.com", "age": 28}
}
# 缓存操作相关函数
async def get_from_cache(key: str):
    """从缓存中获取数据"""
    try:
        return await redis_manager.redis.get(key)
    except:
        return None

async def set_to_cache(key: str, value: str, expire:int = 300):
    """将数据保存到缓存中"""
    try:
        await redis_manager.redis.setex(key, value, expire)
    except:
        pass

async def delete_from_cache(key: str):
    """从缓存中删除数据"""
    try:
        await redis_manager.redis.delete(key)
    except:
        pass

@router.get("/users/{user_id}")
async def get_user(user_id: int):
    """获取用户信息"""
    key = f"user:{user_id}"
    # 从缓存中获取数据
    cached_user = await get_from_cache(key)
    if cached_user:
        user_data = json.loads(cached_user)
        user_data["from_cache"] = True
        return user_data
    # 缓存未命中，从数据库中取
    if user_id in fake_database:
        user_data = fake_database[user_id]
        # 保存到缓存中(缓存中有过期时间的5分钟)
        await set_to_cache(key, json.dumps(user_data))
        user_data["from_cache"] = False
        return user_data
    else:
        raise HTTPException(status_code=404, detail="用户不存在")

@router.put("/users/{user_id}")
async def update_user(user_id: int, user_data: dict):
    """更新用户信息"""
    fake_database[user_id] = user_data
    # 更新缓存
    cache_key = f"user:{user_id}"
    await set_to_cache(cache_key, json.dumps(user_data))
    return {"message": "用户信息已更新"}

@router.delete("/users/{user_id}")
async def delete_user(user_id: int):
    """删除用户"""
    if user_id in fake_database:
        del fake_database[user_id]
        # 删除缓存
        cache_key = f"user:{user_id}"
        await delete_from_cache(cache_key)
        return {"message": "用户已删除"}
    else:
        raise HTTPException(status_code=404, detail="用户不存在")

@router.get("/users/cache/clear")
async def clear_cache():
    """清空缓存"""
    await redis_manager.redis.flushdb()
    return {"message": "缓存已清空"}